package com.example.sql.vo;

import java.util.Queue;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
import com.example.sql.util.StrUtil;

import java.util.HashSet;
import java.util.Set;

public class UpdateWhere {
    private SQLBinaryOpExpr updateParent;
    private SQLExpr originalExpr;
    private SQLExpr replaceExpr;

    public UpdateWhere(SQLBinaryOpExpr updateParent, SQLExpr originalExpr, SQLExpr replaceExpr) {
        this.updateParent = updateParent;
        this.originalExpr = originalExpr;
        this.replaceExpr = replaceExpr;
    }

    public SQLBinaryOpExpr getUpdateParent() {
        return updateParent;
    }

    public void setUpdateParent(SQLBinaryOpExpr updateParent) {
        this.updateParent = updateParent;
    }

    public SQLExpr getOriginalExpr() {
        return originalExpr;
    }

    public void setOriginalExpr(SQLExpr originalExpr) {
        this.originalExpr = originalExpr;
    }

    public SQLExpr getReplaceExpr() {
        return replaceExpr;
    }

    public void setReplaceExpr(SQLExpr replaceExpr) {
        this.replaceExpr = replaceExpr;
    }

    public void doUpdate() {
        // del 旧节点
        originalExpr.setParent(null);

        // 判断在左边还是右边
        if (updateParent.getLeft() == originalExpr) {
            // add 新节点
            SQLExpr orQuery = SQLUtils.toSQLExpr(originalExpr.toString() + " or " + replaceExpr.toString());
            updateParent.setLeft(orQuery);

        } else if (updateParent.getRight() == originalExpr) {
            // add 新节点
            SQLExpr orQuery = SQLUtils.toSQLExpr(originalExpr.toString() + " or " + replaceExpr.toString());
            updateParent.setRight(orQuery);
        } else {
            throw new RuntimeException("更新条件未匹配到原来的树节点");
        }
    }

    private static Set<String> orColumns = Set.of("pk_mandept", "pk_usedept");

    public static void addQueue(Queue<WhereWrapper> whereQueue, SQLIdentifierExpr identifierExpr) {

        if (orColumns.contains(identifierExpr.getName())) {
            if (identifierExpr.getParent() instanceof SQLExpr parent) {
                WhereWrapper whereWrapper = new WhereWrapper(identifierExpr.getName(), identifierExpr, parent);
                whereQueue.add(whereWrapper);
            }
        }
    }

    public static void addQueue(Queue<WhereWrapper> whereQueue, SQLPropertyExpr propertyExpr) {

        if (orColumns.contains(propertyExpr.getName())) {
            if (propertyExpr.getParent() instanceof SQLExpr parent) {
                WhereWrapper whereWrapper = new WhereWrapper(propertyExpr.getName(), propertyExpr, parent);
                whereQueue.add(whereWrapper);
            }
        }
    }

    public static void pollQueue(Queue<WhereWrapper> whereQueue, Queue<UpdateWhere> afterUpdateWhereQueue) {

        if (!whereQueue.isEmpty()) {
            while (whereQueue.peek() != null) {
                UpdateWhere.toNewWhereSql(whereQueue.poll(), afterUpdateWhereQueue);
            }
        }
    }

    public static void toNewWhereSql(WhereWrapper whereWrapper, Queue<UpdateWhere> afterUpdateWhereQueue) {
        deleteUsedept(whereWrapper);

        SQLExpr where = whereWrapper.getWhere();
        String columnName = whereWrapper.getName();
        String originalWhere = whereWrapper.getColumnExpr().toString();
        String newSql = where.toString().replace(originalWhere, "t5." + columnName);

        SQLExpr newExpr = SQLUtils.toSQLExpr(newSql);
        SQLObject updateParent = where.getParent();

        if (updateParent instanceof SQLBinaryOpExpr updateBinOpExpr) {
            UpdateWhere updateWhere = new UpdateWhere(updateBinOpExpr, where, newExpr);
            afterUpdateWhereQueue.add(updateWhere);
        }
    }

    /**
     * 删除无效中间层表，将其下级条件替换其自身
     * 
     * @param whereWrapper
     */
    public static void deleteUsedept(WhereWrapper whereWrapper) {
        SQLExpr where = whereWrapper.getWhere();
        String columnName = whereWrapper.getName();
        SQLExpr originalExpr = whereWrapper.getColumnExpr();

        if (columnName.equals("pk_mandept")) {
            if (where instanceof SQLInSubQueryExpr topSubQueryExpr) {
                DeleteUsedeptSubQueryVisitor deleteUsedeptSubQueryVisitor = new DeleteUsedeptSubQueryVisitor(
                        topSubQueryExpr);
                topSubQueryExpr.accept(deleteUsedeptSubQueryVisitor);

                whereWrapper.setWhere(deleteUsedeptSubQueryVisitor.getRetExpr());
            }
        }
    }

    private static class DeleteUsedeptSubQueryVisitor extends OracleASTVisitorAdapter {
        SQLInSubQueryExpr topSubQueryExpr;

        SQLExpr retExpr;

        public DeleteUsedeptSubQueryVisitor(SQLInSubQueryExpr topSubQueryExpr) {
            this.topSubQueryExpr = topSubQueryExpr;
            this.retExpr = topSubQueryExpr;
        }

        // SQLSelect/OracleSelectQueryBlock/getFrom(OracleSelectQueryBlock)|getWhere(SQLInSubQueryExpr)

        public boolean visit(OracleSelectTableReference tableRef) {
            if (tableRef.getName().getSimpleName().equals("scaledept")) {
                if (tableRef.getParent() instanceof OracleSelectQueryBlock selectQueryBlock) {
                    // 真实条件=子查询
                    if (selectQueryBlock.getWhere() instanceof SQLInSubQueryExpr subQueryExpr) {
                        topSubQueryExpr.setSubQuery(subQueryExpr.getSubQuery());
                        retExpr = topSubQueryExpr;
                    } 
                    // 真实条件=二元操作符
                    else  if (selectQueryBlock.getWhere() instanceof SQLBinaryOpExpr binOpExpr) {
                        if (topSubQueryExpr.getParent() instanceof SQLBinaryOpExpr parent) {

                            SQLBinaryOpExpr addOpExpr = new SQLBinaryOpExpr();
                            // 如果别名为空则将表名做别名处理
                            addOpExpr.setLeft(topSubQueryExpr.getExpr());
                            addOpExpr.setOperator(binOpExpr.getOperator());
                            addOpExpr.setRight(binOpExpr.getRight());
                            if (topSubQueryExpr == parent.getLeft()) {
                                parent.setLeft(addOpExpr);
                            } else if (topSubQueryExpr == parent.getRight()) {
                                parent.setRight(addOpExpr);
                            }

                            topSubQueryExpr.setParent(null);
                            retExpr = addOpExpr;
                        }
                    }
                }
            }
            return false;
        }

        public SQLExpr getRetExpr() {
            return retExpr;
        }
    }
}
